package com.yunkeji.api.wall.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.baomidou.lock.executor.RedissonLockExecutor;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.cache.LoadingCache;
import com.yunkeji.api.wall.bo.PageLikeWallBo;
import com.yunkeji.api.wall.bo.PubLikeWallBo;
import com.yunkeji.api.wall.mapper.ApiLikeWallMapper;
import com.yunkeji.api.wall.service.LikesWallService;
import com.yunkeji.api.wall.vo.LikeWallVo;
import com.yunkeji.common.constant.CacheConstants;
import com.yunkeji.common.core.page.TableDataInfo;
import com.yunkeji.common.enums.LikeWallCheckEnums;
import com.yunkeji.common.enums.app.CheckStatus;
import com.yunkeji.common.exception.AppServiceException;
import com.yunkeji.common.helper.LoginHelper;
import com.yunkeji.common.msg.PushMessage;
import com.yunkeji.common.msg.bo.PrivateMsg;
import com.yunkeji.common.msg.utils.BadWordDetectorUtils;
import com.yunkeji.dao.domain.*;
import com.yunkeji.dao.mapper.AppUserExtMapper;
import com.yunkeji.dao.mapper.LikeWallDetailMapper;
import com.yunkeji.dao.mapper.SysCityMapper;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/** @author 老张 */
@Service
@AllArgsConstructor
public class LikesWallServiceImpl implements LikesWallService {

    private final AppUserExtMapper appUserExtMapper;
    private final SysCityMapper sysCityMapper;;
    private final ApiLikeWallMapper apiLikeWallMapper;
    private final LockTemplate lockTemplate;
    private final LikeWallDetailMapper likeWallDetailMapper;

    @Resource(name = "sensitiveWordCheck")
    LoadingCache<String, BadWordDetectorUtils> sensitiveWordCheck;
    /**
     * 发布
     *
     * @author 老张
     */
    @Override
    @SneakyThrows
    public void pubLikesWall(PubLikeWallBo bo) {
        Set<String> badWords =
                sensitiveWordCheck.get(CacheConstants.SENSITIVE_WORD).getBadWords(bo.getContent());
        if (badWords.size() > 0) {
            throw AppServiceException.paramException("不允许发送关键字:" + badWords.toString());
        } else {
            boolean checkAgain = BadWordDetectorUtils.checkAgain(bo.getContent());
            if (checkAgain) {
                throw AppServiceException.paramException("文本包含不允许发送的关键词");
            }
        }
        AppUserExt appUserExt = appUserExtMapper.selectById(LoginHelper.getUserId());
        LikeWall likeWall = BeanUtil.toBean(appUserExt, LikeWall.class);
        likeWall.setId(null);
        likeWall.setPlatformId(LoginHelper.getPlatformId());
        likeWall.setStatus(LikeWallCheckEnums.待审核.getCode());
        likeWall.setUserId(LoginHelper.getUserId());
        likeWall.setContent(bo.getContent());
        likeWall.setType(bo.getType());
        likeWall.setNickName(appUserExt.getNickName());
        likeWall.setPubHeadUrl(appUserExt.getHeadUrl());
        SysCity sysCity = sysCityMapper.selectById(appUserExt.getLiveCity());
        likeWall.setCityName(sysCity != null ? sysCity.getName() : "未知城市");
        apiLikeWallMapper.insert(likeWall);
    }

    /**
     * 分页
     *
     * @author 老张
     */
    @Override
    public TableDataInfo<LikeWallVo> list(PageLikeWallBo bo) {
        Page<LikeWallVo> list =
                apiLikeWallMapper.list(bo.build(), bo, null, CheckStatus.审核通过.getCode());

        List<LikeWallVo> records = list.getRecords();
        if (records.size() > 0) {
            // 检查是否点赞
            List<Long> ids = records.stream().map(LikeWallVo::getId).collect(Collectors.toList());
            List<LikeWallDetail> likeWallDetails =
                    likeWallDetailMapper.selectList(
                            Wrappers.lambdaQuery(LikeWallDetail.class)
                                    .eq(LikeWallDetail::getUserId, LoginHelper.getUserId())
                                    .in(LikeWallDetail::getWallId, ids));
            if (likeWallDetails.size() > 0) {
                Map<Long, LikeWallDetail> collect =
                        likeWallDetails.stream()
                                .collect(Collectors.toMap(LikeWallDetail::getWallId, item -> item));
                records.forEach(
                        item -> {
                            item.setLikeFlag(collect.get(item.getId()) == null ? 0 : 1);
                        });
            }
        }

        return TableDataInfo.build(list);
    }

    /**
     * 点赞，放弃联查，每次点赞把头像放在点赞表
     *
     * @author 老张
     * @param baseId
     */
    @Override
    public void toLike(BaseId baseId) {
        LikeWall likeWall = apiLikeWallMapper.selectById(baseId.getId());
        if (likeWall == null && likeWall.getStatus().equals(LikeWallCheckEnums.审核通过.getCode())) {
            throw AppServiceException.paramException("贴贴墙未找到");
        }
        LikeWallDetail detail =
                likeWallDetailMapper.selectOne(
                        Wrappers.lambdaQuery(LikeWallDetail.class)
                                .select(LikeWallDetail::getWallId)
                                .eq(LikeWallDetail::getWallId, baseId.getId())
                                .eq(LikeWallDetail::getUserId, LoginHelper.getUserId()));

        final LockInfo lockInfo =
                lockTemplate.lock(
                        CacheConstants.REDIS_LOCK_LIKE + baseId.getId(),
                        30000L,
                        5000L,
                        RedissonLockExecutor.class);
        if (null == lockInfo) {
            throw new RuntimeException("业务处理中,请稍后再试");
        }
        // 获取锁成功，处理业务
        try {
            if (detail == null) {
                // 点赞
                apiLikeWallMapper.addLikes(baseId.getId());

                LikeWallDetail likeWallDetail = new LikeWallDetail();
                likeWallDetail.setUserId(LoginHelper.getUserId());
                likeWallDetail.setWallId(baseId.getId());
                likeWallDetail.setCreateTime(new Date().getTime());
                likeWallDetailMapper.insert(likeWallDetail);
                culHead(baseId.getId());

                // TODO 发布通知
                if (!LoginHelper.getPlatformId().equals(likeWall.getPlatformId())) {
                    AppUserExt appUserExt = appUserExtMapper.selectById(LoginHelper.getUserId());
                    PushMessage.sendTextSingleSysSquare(
                            likeWall.getPlatformId(),
                            PrivateMsg.builder()
                                    .content("您收到一个新的贴贴")
                                    .nickname(appUserExt.getNickName())
                                    .headUrl(appUserExt.getHeadUrl())
                                    .id(appUserExt.getId())
                                    .platformId(LoginHelper.getPlatformId())
                                    .build());
                }
            } else {
                throw AppServiceException.paramException("您已经点过赞了");
                //                // 取消点赞
                //                apiLikeWallMapper.subLikes(baseId.getId());
                //                likeWallDetailMapper.delete(
                //                        Wrappers.lambdaQuery(LikeWallDetail.class)
                //                                .select(LikeWallDetail::getWallId)
                //                                .eq(LikeWallDetail::getWallId, baseId.getId())
                //                                .eq(LikeWallDetail::getUserId,
                // LoginHelper.getUserId()));
            }
            // 重新计算最近点赞
            culHead(baseId.getId());
        } finally {
            // 释放锁
            lockTemplate.releaseLock(lockInfo);
        }
    }

    /**
     * 计算最近点赞的头像
     *
     * @author 老张
     * @param wallId
     */
    private void culHead(Long wallId) {
        List<LikeWallDetail> likeWallDetails =
                likeWallDetailMapper.selectList(
                        Wrappers.lambdaQuery(LikeWallDetail.class)
                                .select(LikeWallDetail::getUserId)
                                .eq(LikeWallDetail::getWallId, wallId)
                                .orderBy(true, false, LikeWallDetail::getCreateTime)
                                .last(" limit 5"));
        List<String> headList = ListUtil.empty();
        if (CollectionUtil.isNotEmpty(likeWallDetails)) {
            List<Long> collect =
                    likeWallDetails.stream()
                            .map(LikeWallDetail::getUserId)
                            .collect(Collectors.toList());
            headList =
                    appUserExtMapper
                            .selectList(
                                    Wrappers.lambdaQuery(AppUserExt.class)
                                            .select(AppUserExt::getHeadUrl)
                                            .ne(AppUserExt::getHeadUrl, "")
                                            .isNotNull(AppUserExt::getHeadUrl)
                                            .in(AppUserExt::getId, collect))
                            .stream()
                            .map(AppUserExt::getHeadUrl)
                            .collect(Collectors.toList());
        }
        LikeWall newLikeWall = new LikeWall();
        newLikeWall.setId(wallId);
        newLikeWall.setHeadInfo(headList);
        apiLikeWallMapper.updateById(newLikeWall);
    }

    /**
     * 删除
     *
     * @author 老张
     */
    @Override
    public void delWall(BaseId bo) {
        apiLikeWallMapper.delete(
                Wrappers.lambdaQuery(LikeWall.class)
                        .eq(LikeWall::getUserId, LoginHelper.getUserId())
                        .eq(LikeWall::getId, bo.getId()));
    }

    /**
     * 我的
     *
     * @author 老张
     */
    @Override
    public TableDataInfo<LikeWallVo> listMine(PageLikeWallBo bo) {
        Page<LikeWallVo> list =
                apiLikeWallMapper.list(bo.build(), bo, LoginHelper.getUserId(), null);
        return TableDataInfo.build(list);
    }

    /**
     * 删除所有
     *
     * @author 老张
     */
    @Override
    public void delWallAll() {
        apiLikeWallMapper.delete(
                Wrappers.lambdaQuery(LikeWall.class)
                        .eq(LikeWall::getUserId, LoginHelper.getUserId()));
    }
}
